
package com.wisevar.thirdplatform.gateway.aspect;

import cn.hutool.core.util.StrUtil;
import com.wisevar.thirdplatform.gateway.constant.CommonConstant;
import com.wisevar.thirdplatform.gateway.exception.BaseException;
import com.wisevar.thirdplatform.gateway.exception.ParamException;
import com.wisevar.thirdplatform.gateway.model.common.ResultCode;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@Order(1)
@Aspect
@Component
public class OpenApiRateLimitAspect {

    @Autowired
    private RedissonClient redissonClient;

    public static final String OPEN_API_RATE_LIMIT_PATTERN = CommonConstant.SERVICE_NAME + ":OpenApiRateLimit:%s:%s:%s:%s";

    @Pointcut("@annotation(com.wisevar.thirdplatform.gateway.aspect.OpenApiRateLimit)")
    private void openApiRateLimitPointCut() {
    }

    @Before("openApiRateLimitPointCut() && @annotation(openApiRateLimit)")
    public void doBefore(OpenApiRateLimit openApiRateLimit) throws Throwable {
        String limiterName = getOpenApiRateLimiterName(openApiRateLimit);
        RRateLimiter myRateLimiter = redissonClient.getRateLimiter(limiterName);
        myRateLimiter.trySetRate(RateType.OVERALL, openApiRateLimit.count(), openApiRateLimit.timeInterval(), RateIntervalUnit.SECONDS);
        boolean tryAcquire = myRateLimiter.tryAcquire(1);
        if (!tryAcquire) {
            throw new BaseException(ResultCode.TOO_MANY_REQUEST);
        }
    }

    private String getOpenApiRateLimiterName(OpenApiRateLimit openApiRateLimit) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String clientId = request.getHeader("client-id");
        if (StrUtil.isEmpty(clientId)) {
            throw new ParamException("client-id 不能为空");
        }
        String requestURI = request.getRequestURI();
        return String.format(OPEN_API_RATE_LIMIT_PATTERN, requestURI, clientId, openApiRateLimit.timeInterval(), openApiRateLimit.count());
    }

}
